<template>
  <AsyncComponent v-bind="asyncProps">
    <slot v-for="slot of slotKeys" :name="slot"></slot>
  </AsyncComponent>
</template>

<script lang="ts" setup>
import {
    AsyncComponentLoader,
    PropType,
    defineAsyncComponent,
    ref,
    useAttrs,
    watch,
    useSlots,
    provide,
    h
} from "vue";
// @ts-ignore
import { loadModule, Options, AbstractPath } from "vue3-sfc-loader";
import { randomString, isHttpLink, handleSplitter } from "@/utils";
import axios, { AxiosRequestConfig } from "axios";
const props = defineProps({
    apiPrefix: {
        type: String, default: "", required: false
    },
    filename: {
        type: String, default: "", required: true
    },
    filepath: {
        type: String, default: "", required: false
    },
    modules:{
        type: Object, default: ()=>{}, required: false
    },
    devMode:{
        type: Boolean, default: false, required: false
    },
    asyncProps:{
        type: Object, default: ()=>{}, required: false
    },
    axiosConfig:{
        type: Object as PropType<AxiosRequestConfig>, default: ()=>{}, required: false
    },
    file: {
        type: String, default: "", required: false
    },
    files: {
        type: Object, default: ()=>{}, required: false
    }
})

const emit = defineEmits<{
    log: [string,any]
    customBlockHandler: [any,string,Options],
}>()

const slotKeys = Object.keys(useSlots())

const showError = ref(false)
const errorMsg = ref("")

const loadSvg  = (name: string) => {
    const importVuePath = './' + name + '.svg';
    const svgPromise = () => import(/* @vite-ignore */importVuePath)
    const svg = ref();
    watch(() => svgPromise(), promise => promise.then(value => svg.value = value), { immediate: true });
    return svg;
}

const file = props.file
const asyncProps = { ...props.asyncProps, ...useAttrs() };
const axiosConfig = props.axiosConfig as AxiosRequestConfig;
const files = props.files || {};
const apiPrefix = handleSplitter(props.apiPrefix||"");
const filepath = handleSplitter(props.filepath||"");
const filename = props.filename?.toString().replace(".vue","")+".vue";
const getFile = async (url:any)=>{
    if (isHttpLink(url.toString())){
        return fetch(url).then(res => res.text());
    }else if (files[url]){
        return Promise.resolve(files[url])
    }else if(file){
        return Promise.resolve(file)
    }else{
        return new Promise((resolve, reject) => {
            const httpUrl = apiPrefix+filepath+`?filename=${filename}&filepath=${filepath}`
            axios.get(httpUrl, axiosConfig).then((res)=>resolve(res.data)).catch((error)=>{
                showError.value = true
                // console.log(error)
                // resolve(`<template><div>123</div></template>`)
                reject(error)
                // reject()
            });
        })
    }
}
const addStyle = (styleStr: string, _?: string)=>{
    const style = document.createElement('style');
    style.textContent = styleStr;
    const ref = document.head.getElementsByTagName('style')[0] || null;
    if (ref){
        document.head.insertBefore(style, ref);
    }
}

const log = (type: string, ...args: any)=>{
    emit("log", type,args)
}

const customBlockHandler = (block:any, filename:string, options:Options)=>{
    emit("customBlockHandler", block, filename, options)
}

// @ts-ignore
const handleModule = async (type: string, resource:any, path: AbstractPath, options: Options)=>{
    switch (type) {
        case '.json':
            return JSON.parse(resource);
        case '.css':
            options.addStyle(await resource(false),"");
            return null;
        case '.svg':
            return resource(false);
    }
}



const baseOptions: any = {
    devMode: props.devMode || false,
    moduleCache: {
        vue: window.Vue,
        axios: window.axios,
        ...props.modules,
    },
    addStyle,
    customBlockHandler,
    getFile,
    log,
    handleModule
} as Options

const defineAsyncLoader = (path: AbstractPath, options:Options = {} as Options)=>{
    return loadModule(path, Object.assign(baseOptions,options))
}

provide("APP_TOOLS", {
    ...window.VueShared,
    loadSvg,
    defineAsyncLoader,
    handleSplitter,
    randomString,
    isHttpLink,
})

const loader: AsyncComponentLoader = ()=> defineAsyncLoader(filepath +"/"+ filename)


    // IframePage
const AsyncComponent = defineAsyncComponent({
    loader,
    // loadingComponent: Loading,
    delay: 200,
    timeout: 10000,
    // @ts-ignore
    errorComponent: h(IframePage,{ modelValue: showError.value, content: errorMsg.value })
})
</script>

<style scoped>

</style>
